package cn.ycc1.functionlibrary.streams;

/**
 * Implementing the Collector Interface
 * @author ycc
 * @date 2025/3/8
 */
public class ImplementingCollector {
    /**
     * Why Would You Implement the Collector Interface?
     * There are three ways to create your own collector.
     *
     * We examined a first one in this tutorial. It consists of combining existing collectors with the different mechanisms
     * offered by the Collectors factory class, namely passing a collector as a downstream collector to another collector or
     * using a finisher with the collectingAndThen() collector.
     *
     * You can also call the collect() method that takes the three elements upon which a collector is built. These methods are
     * available on both the streams of primitive types and the stream of objects. They take the three arguments we presented in
     * the previous sections.
     *
     * The supplier used to create the mutable container in which the elements of the stream are accumulated.
     * The accumulator, modeled by a biconsumer.
     * The combiner, also modeled by a bi-consumer, used to combine two partially filled containers, used in the case of parallel
     * streams.
     * The third way consists in implementing the Collector interface yourself, and pass your implementation to the collect()
     * method we already covered. Implementing your own collector gives you maximum flexibility, but it is also more technical.
     */

    /**
     * Understanding the Parameter Types of Collector
     * Let us first examine the following types: T and R.
     *
     * The first type is T, and it corresponds to the type of the elements of the stream this collector is processing.
     *
     * The last type is R, and it is the type produced by this collector.
     *
     * For the toList() collector, called on an instance of Stream, the type R would be List<T>. It would be Set<T> for the
     * toSet() collector.
     *
     * The groupingBy() method takes a function to compute the keys of the returned map. If you are collecting a Stream with
     * this collector, then you need to pass a function that can map instances of T. It can map them to any instance of type K
     * to create the keys of the map. So the type of the resulting map will be Map<K, List<T>>. So the type R is just this one:
     * Map<K, List<T>>.
     *
     * The type A is more complex to handle. You may have tried to use your IDE to store one of the collectors you created in the
     * previous examples. If you did that, you probably realized that your IDE did not give an explicit value for this type.
     * This is the case for the following examples.
     */

    /**
     * Understanding the Characteristics of a Collector
     * A collector defines internal characteristics that are used by the stream implementation to optimize the use of this
     * collector.
     *
     * There are three characteristics.
     *
     * The IDENTITY_FINISH characteristic indicates that the finisher of this collector is the identity function.
     * The implementation will not call the finisher for a collector with this characteristic.
     * The UNORDERED characteristic indicates that this collector does not preserve the order in which it processes the elements
     * of the stream. This is the case for the toSet() collector, which has this characteristic. The toList() collector,
     * on the other hand, does not have it.
     * The CONCURRENT characteristic indicates that the container in which the accumulator stores the processed elements supports
     * concurrent access. This point is important for parallel streams.
     * These characteristics are defined in the Collector.Characteristics enumeration and are returned in a set by the
     * characteristics() method defined on the Collector interface.
     */

    /**
     * Implementing the toList() and toSet() Collector
     * With these elements, you can now recreate an implementation of a collector that works like the toList() collector.
     */

    /**
     * Implementing the joining() Collector
     * Recreating the implementation of this collector is interesting because it only operates on strings, and its finisher is
     * not the identity function.
     *
     * This collector accumulates the strings it processes in an instance of StringBuffer and then calls the toString() method
     * on this accumulator to produce the final result.
     *
     * The set of characteristics is empty for this collector. It does preserve the order in which the elements are processed
     * (so no UNORDERED characteristics), its finisher is not the identity function, and it cannot be used concurrently.
     */


}
